﻿using System.Drawing;
using Auxiliary.VecMath;
using Simple3DRedactor.Domain;
using Tao.OpenGl;

namespace Simple3DRedactor.OpenGLViewer
{
    class LightView : ObjectView<Light>
    {
        private readonly ObjectViewFactory _factory;
        private readonly Glu.GLUquadric _quadric = Glu.gluNewQuadric();
        private const float Radius = 1.0f;

        public LightView(Light obj, ObjectViewFactory factory)
            : base(obj)
        {
            _factory = factory;
            Id = factory.RegisterNewObject(this);
            LightId = factory.GetNewLightId();
        }

        public override void OnRemove()
        {
            base.OnRemove();
            _factory.ReturnLightId(LightId);
        }

        public int Id { get; private set; }

        public int LightId { get; private set; }

        public override void Setup()
        {
            Gl.glEnable(Gl.GL_LIGHT0 + LightId);

            SetupLightColor(Gl.GL_AMBIENT, InnerObject.Ambient);
            SetupLightColor(Gl.GL_DIFFUSE, InnerObject.Diffuse);
            SetupLightColor(Gl.GL_SPECULAR, InnerObject.Specular);

            Gl.glLightfv(Gl.GL_LIGHT0 + LightId, Gl.GL_POSITION, new[] { InnerObject.Position.X, InnerObject.Position.Y, InnerObject.Position.Z, 1.0f });

            Gl.glLightf(Gl.GL_LIGHT0 + LightId, Gl.GL_CONSTANT_ATTENUATION, InnerObject.ConstantAttenuation);
            Gl.glLightf(Gl.GL_LIGHT0 + LightId, Gl.GL_LINEAR_ATTENUATION, InnerObject.LinearAttenuation);
            Gl.glLightf(Gl.GL_LIGHT0 + LightId, Gl.GL_QUADRATIC_ATTENUATION, InnerObject.QuadraticAttenuation);

            Gl.glLightf(Gl.GL_LIGHT0 + LightId, Gl.GL_SPOT_CUTOFF, InnerObject.SpotCutOff);
            Gl.glLightf(Gl.GL_LIGHT0 + LightId, Gl.GL_SPOT_EXPONENT, InnerObject.SpotExponent);
        }

        private void SetupLightColor(int pname, Color c)
        {
            Gl.glLightfv(Gl.GL_LIGHT0 + LightId, pname, new[] { c.R / 255.0f, c.G / 255.0f, c.B / 255.0f, c.A / 255.0f });
        }

        protected override void PreRenderImpl()
        {
            Gl.glColor3f(InnerObject.Diffuse.R / 255.0f, InnerObject.Diffuse.G / 255.0f, InnerObject.Diffuse.B / 255.0f);

            Gl.glLoadName(Id);
        }

        protected override void RenderImpl()
        {
            Gl.glPushAttrib(Gl.GL_LIGHTING_BIT);
            Gl.glDisable(Gl.GL_LIGHTING);
            Glu.gluSphere(_quadric, Radius, 50, 50);
            Gl.glPopAttrib();
        }

        protected override void PostRenderImpl()
        {
        }

        protected override Vector3D MaxPoint
        {
            get { return new Vector3D(Radius, Radius, Radius); }
        }

        protected override Vector3D MinPoint
        {
            get { return new Vector3D(-Radius, -Radius, -Radius); }
        }
    }
}
